/**
 ******************************************************************************
 * @file           : bsp_dma.c
 * @brief          : DMA Driver Implementation (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * DMA驱动程序实现文件
 * 提供DMA配置和管理接口
 * 支持内存到内存、外设到内存、内存到外设传输
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/DMA/bsp_dma.h"
#include "./BSP/DMA/bsp_dma_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DMA_TRANSFER_TIMEOUT        5000        /*!< DMA传输超时时间(ms) */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static DMA_HandleTypeDef sg_dma_handle[8];                  /*!< DMA句柄数组 */
static volatile uint8_t sg_dma_initialized[8] = {0};        /*!< DMA初始化标志 */
static volatile uint8_t sg_dma_busy[8] = {0};               /*!< DMA忙标志 */

/* Private function prototypes -----------------------------------------------*/
static uint32_t dma_get_data_width(DMA_DataWidth_e width);
static uint32_t dma_get_priority(DMA_Priority_e priority);
static uint32_t dma_get_direction(DMA_Direction_e direction);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       获取DMA数据宽度
 *
 * @param[in]   width DMA数据宽度枚举
 *
 * @retval      uint32_t HAL库数据宽度
 */
static uint32_t dma_get_data_width(DMA_DataWidth_e width)
{
    switch (width)
    {
        case DMA_DATA_WIDTH_BYTE:
            return DMA_PDATAALIGN_BYTE;
        case DMA_DATA_WIDTH_HALFWORD:
            return DMA_PDATAALIGN_HALFWORD;
        case DMA_DATA_WIDTH_WORD:
            return DMA_PDATAALIGN_WORD;
        default:
            return DMA_PDATAALIGN_BYTE;
    }
}

/**
 * @brief       获取DMA优先级
 *
 * @param[in]   priority DMA优先级枚举
 *
 * @retval      uint32_t HAL库优先级
 */
static uint32_t dma_get_priority(DMA_Priority_e priority)
{
    switch (priority)
    {
        case DMA_PRIORITY_LOW:
            return DMA_PRIORITY_LOW;
        case DMA_PRIORITY_MEDIUM:
            return DMA_PRIORITY_MEDIUM;
        case DMA_PRIORITY_HIGH:
            return DMA_PRIORITY_HIGH;
        case DMA_PRIORITY_VERY_HIGH:
            return DMA_PRIORITY_VERY_HIGH;
        default:
            return DMA_PRIORITY_LOW;
    }
}

/**
 * @brief       获取DMA传输方向
 *
 * @param[in]   direction DMA传输方向枚举
 *
 * @retval      uint32_t HAL库传输方向
 */
static uint32_t dma_get_direction(DMA_Direction_e direction)
{
    switch (direction)
    {
        case DMA_DIR_PERIPH_TO_MEMORY:
            return DMA_PERIPH_TO_MEMORY;
        case DMA_DIR_MEMORY_TO_PERIPH:
            return DMA_MEMORY_TO_PERIPH;
        case DMA_DIR_MEMORY_TO_MEMORY:
            return DMA_MEMORY_TO_MEMORY;
        default:
            return DMA_PERIPH_TO_MEMORY;
    }
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       DMA初始化和配置
 *
 * @param[in]   config DMA配置结构体指针
 *
 * @retval      DMA_OK 成功
 * @retval      DMA_ERROR_PARAM 参数错误
 * @retval      DMA_ERROR_TRANSFER 传输错误
 *
 * @note        根据配置结构体初始化DMA
 */
DMA_Error_e dma_init(const DMA_Config_t *config)
{
    if (config == NULL || config->stream == NULL)
    {
        log_w("DMA初始化参数错误");
        return DMA_ERROR_PARAM;
    }
    
    if (config->data_num == 0)
    {
        log_w("DMA数据数量为0");
        return DMA_ERROR_PARAM;
    }
    
    /* 使能DMA时钟 */
    __HAL_RCC_DMA1_CLK_ENABLE();
    __HAL_RCC_DMA2_CLK_ENABLE();
    
    /* 配置DMA句柄 */
    sg_dma_handle[0].Instance = config->stream;
    sg_dma_handle[0].Init.Request = DMA_REQUEST_MEM2MEM;
    sg_dma_handle[0].Init.Direction = dma_get_direction(config->direction);
    sg_dma_handle[0].Init.PeriphInc = config->periph_inc ? DMA_PINC_ENABLE : DMA_PINC_DISABLE;
    sg_dma_handle[0].Init.MemInc = config->memory_inc ? DMA_MINC_ENABLE : DMA_MINC_DISABLE;
    sg_dma_handle[0].Init.PeriphDataAlignment = dma_get_data_width(config->periph_width);
    sg_dma_handle[0].Init.MemDataAlignment = dma_get_data_width(config->memory_width);
    sg_dma_handle[0].Init.Mode = (config->mode == DMA_MODE_CIRCULAR) ? DMA_CIRCULAR : DMA_NORMAL;
    sg_dma_handle[0].Init.Priority = dma_get_priority(config->priority);
    sg_dma_handle[0].Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    
    if (HAL_DMA_Init(&sg_dma_handle[0]) != HAL_OK)
    {
        log_e("DMA初始化失败");
        return DMA_ERROR_TRANSFER;
    }
    
    sg_dma_initialized[0] = 1;
    log_d("DMA初始化成功: stream=%p", config->stream);
    return DMA_OK;
}

/**
 * @brief       DMA反初始化
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      DMA_OK 成功
 * @retval      DMA_ERROR_PARAM 参数错误
 *
 * @note        关闭DMA
 */
DMA_Error_e dma_deinit(DMA_Stream_TypeDef *stream)
{
    if (stream == NULL)
    {
        log_w("DMA反初始化参数错误");
        return DMA_ERROR_PARAM;
    }
    
    HAL_DMA_DeInit(&sg_dma_handle[0]);
    sg_dma_initialized[0] = 0;
    sg_dma_busy[0] = 0;
    
    log_d("DMA已反初始化: stream=%p", stream);
    return DMA_OK;
}

/**
 * @brief       启动DMA传输
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      DMA_OK 成功
 * @retval      DMA_ERROR_PARAM 参数错误
 * @retval      DMA_ERROR_BUSY DMA忙
 * @retval      DMA_ERROR_TRANSFER 传输错误
 *
 * @note        启动DMA传输
 */
DMA_Error_e dma_start(DMA_Stream_TypeDef *stream)
{
    if (stream == NULL)
    {
        log_w("DMA启动参数错误");
        return DMA_ERROR_PARAM;
    }
    
    if (sg_dma_busy[0])
    {
        log_w("DMA正在传输");
        return DMA_ERROR_BUSY;
    }
    
    if (HAL_DMA_Start(&sg_dma_handle[0], 0, 0, 0) != HAL_OK)
    {
        log_e("DMA启动失败");
        return DMA_ERROR_TRANSFER;
    }
    
    sg_dma_busy[0] = 1;
    log_d("DMA已启动: stream=%p", stream);
    return DMA_OK;
}

/**
 * @brief       停止DMA传输
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      DMA_OK 成功
 * @retval      DMA_ERROR_PARAM 参数错误
 * @retval      DMA_ERROR_TRANSFER 传输错误
 *
 * @note        停止DMA传输
 */
DMA_Error_e dma_stop(DMA_Stream_TypeDef *stream)
{
    if (stream == NULL)
    {
        log_w("DMA停止参数错误");
        return DMA_ERROR_PARAM;
    }
    
    if (HAL_DMA_Abort(&sg_dma_handle[0]) != HAL_OK)
    {
        log_e("DMA停止失败");
        return DMA_ERROR_TRANSFER;
    }
    
    sg_dma_busy[0] = 0;
    log_d("DMA已停止: stream=%p", stream);
    return DMA_OK;
}

/**
 * @brief       DMA传输
 *
 * @param[in]   stream DMA流指针
 * @param[in]   src_addr 源地址
 * @param[in]   dst_addr 目标地址
 * @param[in]   data_num 数据数量
 *
 * @retval      DMA_OK 成功
 * @retval      DMA_ERROR_PARAM 参数错误
 * @retval      DMA_ERROR_BUSY DMA忙
 * @retval      DMA_ERROR_TRANSFER 传输错误
 *
 * @note        执行DMA传输
 */
DMA_Error_e dma_transfer(DMA_Stream_TypeDef *stream, uint32_t src_addr, uint32_t dst_addr, uint32_t data_num)
{
    if (stream == NULL || src_addr == 0 || dst_addr == 0 || data_num == 0)
    {
        log_w("DMA传输参数错误");
        return DMA_ERROR_PARAM;
    }
    
    if (sg_dma_busy[0])
    {
        log_w("DMA正在传输");
        return DMA_ERROR_BUSY;
    }
    
    if (HAL_DMA_Start(&sg_dma_handle[0], src_addr, dst_addr, data_num) != HAL_OK)
    {
        log_e("DMA传输启动失败");
        return DMA_ERROR_TRANSFER;
    }
    
    sg_dma_busy[0] = 1;
    
    /* 等待传输完成 */
    if (HAL_DMA_PollForTransfer(&sg_dma_handle[0], HAL_DMA_FULL_TRANSFER, DMA_TRANSFER_TIMEOUT) != HAL_OK)
    {
        log_e("DMA传输超时");
        sg_dma_busy[0] = 0;
        return DMA_ERROR_TIMEOUT;
    }
    
    sg_dma_busy[0] = 0;
    log_d("DMA传输成功: src=0x%08lX, dst=0x%08lX, len=%lu", src_addr, dst_addr, data_num);
    return DMA_OK;
}

/**
 * @brief       检查DMA是否忙
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      1 忙
 * @retval      0 空闲
 *
 * @note        快速检查DMA是否正在传输
 */
uint8_t dma_is_busy(DMA_Stream_TypeDef *stream)
{
    (void)stream;
    return sg_dma_busy[0];
}

/**
 * @brief       获取DMA计数器
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      uint32_t 剩余数据数量
 *
 * @note        获取DMA剩余传输数据数量
 */
uint32_t dma_get_counter(DMA_Stream_TypeDef *stream)
{
    if (stream == NULL)
    {
        return 0;
    }
    
    return __HAL_DMA_GET_COUNTER(&sg_dma_handle[0]);
}

/**
 * @brief       DMA传输完成回调（弱函数）
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      无
 *
 * @note        用户可重写此函数处理DMA传输完成事件
 */
__weak void dma_transfer_complete_callback(DMA_Stream_TypeDef *stream)
{
    (void)stream;
    log_i("DMA传输完成");
}

/**
 * @brief       DMA传输错误回调（弱函数）
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      无
 *
 * @note        用户可重写此函数处理DMA传输错误事件
 */
__weak void dma_transfer_error_callback(DMA_Stream_TypeDef *stream)
{
    (void)stream;
    log_e("DMA传输错误");
}

/**
 * @brief       打印DMA状态（用于调试）
 *
 * @param[in]   stream DMA流指针
 *
 * @retval      无
 *
 * @note        显示DMA初始化状态、忙状态等信息
 */
void dma_print_status(DMA_Stream_TypeDef *stream)
{
    if (stream == NULL)
    {
        log_e("DMA状态参数错误");
        return;
    }
    
    log_i("DMA状态:");
    log_i("  初始化状态: %s", sg_dma_initialized[0] ? "已初始化" : "未初始化");
    log_i("  忙状态: %s", sg_dma_busy[0] ? "忙" : "空闲");
    log_i("  剩余数据: %lu", dma_get_counter(stream));
}
